package modelo.juego;

import java.util.LinkedList;
import controlador.Observador;
import controlador.Sujeto;
import modelo.escenario.*;
import modelo.excepciones.InvalidPointValueException;
import modelo.excepciones.UnableToAddElementToListException;
import modelo.excepciones.UnableToRemoveElementFromListException;
import modelo.jugador.*;


public class Juego extends Thread implements modelo.escenario.Escenario, Sujeto{
	/*CONSTANTES*/
	private static final int PUNTOS_GANO_CARRERA = 100;
	private static final int DINERO_GANO_CARRERA = 500;
	private static final int DINERO_PERDIO_CARRERA = -250;
	
	/*ATRIBUTOS*/	
	private int clima;
	private int puntosAdquiridos;
	private double dineroAdquirido;
	private Carrera carrera;
	private Usuario usuario;
	private LinkedList <Observador> observadores;
	
	
	
	/*GETTERS Y SETTERS*/
	public Carrera getCarrera()  { 
		return carrera; 
	}
	
	
	public float getTiempo()  { 
		return carrera.getTiempo(); 
	}
	
	public Jugador getJugador()  { 
		return carrera.getJugador(); 
	}
	
	public int getTipoPista()  { 
		return carrera.getPista().getSuperficie().getTipo(); 
	}
	
	public LinkedList<modelo.jugador.Jugador> getOponentes (){
		return carrera.getOponentes();
	}
	
	/*CONSTRUCTOR*/
	public Juego(Usuario usr, LinkedList <Pista> Pistas){
		/*Inicializaciones*/
		this.usuario = usr;
		
		carrera = new Carrera(usuario, CANTIDAD_OPONENTES);
		carrera.setPista(Calculador.elegirPista(Pistas));
		clima = Calculador.elegirClima();
		carrera.setClima(clima);
		carrera.inicializar();
		
		observadores = new LinkedList <Observador>();
		
		puntosAdquiridos = 0;
		dineroAdquirido = 0;
		
		
	}
	
	/*METODOS PUBLICOS*/
	
	/**
	 * Control del juego en funcionamiento, actualiza la carrera y dibuja la pista
	 */

	public void run(){
		
		
		
		/*Durante el juego*/
		while (carrera.getEstado() == Carrera.JUGANDO || carrera.getEstado() == Carrera.INTRO) {
			
			carrera.actualizar();

			notificarObservadores();

		}
		/*Finalizado el juego*/
		finalizar();
	}
	
	public void finalizar() {
		if (carrera.getEstado() == Carrera.GANO){ //JUAGDOR GANADOR
			puntosAdquiridos = usuario.getPuntos() + PUNTOS_GANO_CARRERA;
			dineroAdquirido = usuario.getDinero() + DINERO_GANO_CARRERA;
		}
		else{ //JUGADOR PERDEDOR
			dineroAdquirido = usuario.getDinero() + DINERO_PERDIO_CARRERA;
		}
		
		/*asignamos puntos y volvemos al menu*/
		try {
			usuario.setPuntos(puntosAdquiridos);
		} 
		catch (InvalidPointValueException e) {} //La constante de puntos es siempre positiva
		usuario.setDinero(dineroAdquirido);
		
		
		
		notificarObservadores();
	}

	
	/*OBSERVADOR*/
	public void notificarObservadores() {
	    if (!observadores.isEmpty()){
			for (Observador obs1 : observadores){
		        obs1.update();
		    }
	    }
	}

	public void registrarObservador(Observador obs) throws UnableToAddElementToListException {
		boolean result = this.observadores.add(obs);
		
		if (!result){
			throw new UnableToAddElementToListException();
		}
	}
	
	public void eliminarObservador(Observador obs) throws UnableToRemoveElementFromListException {
		boolean result = this.observadores.remove(obs);
		
		if(!result){
			throw new UnableToRemoveElementFromListException();
		}
	}
}


